package app

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"log"
	"net/http"
	"strconv"
	"sync"
)

const (
	//点对点聊天
	CMD_SINGLE_MSG = 10
	//群聊
	CMD_ROOM_MSG   = 11
	//心跳
	CMD_HEART      = 0
)
type Message struct {
	Id      int64  `json:"id,omitempty" form:"id"` //消息ID
	Userid  int64  `json:"userid,omitempty" form:"userid"` //谁发的
	Cmd     int    `json:"cmd,omitempty" form:"cmd"` //群聊还是私聊
	Dstid   int64  `json:"dstid,omitempty" form:"dstid"`//对端用户ID/群ID
	Media   int    `json:"media,omitempty" form:"media"` //消息按照什么样式展示
	Content string `json:"content,omitempty" form:"content"` //消息的内容
	Pic     string `json:"pic,omitempty" form:"pic"` //预览图片
	Url     string `json:"url,omitempty" form:"url"` //服务的URL
	Memo    string `json:"memo,omitempty" form:"memo"` //简单描述
	Amount  int    `json:"amount,omitempty" form:"amount"` //其他和数字相关的
}
//本核心在于形成userid和Node的映射关系
type Node struct {
	Conn *websocket.Conn  //socket链接
	//并行转串行,
	DataQueue chan []byte  //数据通道
	GroupSets set.Interface  //系统io
}
var clientMap = make(map[int64]*Node)
//读写锁
var rwlocker sync.RWMutex
//上线一个用户生成一个链接
func Chat(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	id := query.Get("id")
	token := query.Get("token")
	userId ,_ := strconv.ParseInt(id,10,64) //字符串转int64
	isflag := checkToken(userId, token)
	con, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
		return isflag
	},
	}).Upgrade(w,r,nil)
	if nil != err {
		log.Println(err.Error())
		return
	}
	node := &Node{
		Conn:con,
		DataQueue:make(chan [] byte, 50),
		GroupSets:set.New(set.ThreadSafe),
	}
	//加锁
	rwlocker.Lock()
	clientMap[userId] = node
	log.Printf("%s已上线",userId)
	rwlocker.Unlock()
	//启动发送协程
	go sendproc(node)
	//启动接收协程
	go recvproc(node)
	//sendMsg(userId,[]byte("helloword"))
}

/**
验证token
 */
func checkToken(userId int64, token string) bool {

	userToken := UserService.GetToken(userId,false)
	return userToken == token
}

/**
	启动协程发送逻辑
 */
func sendproc(node *Node)  {
	for  {
		select {
		case data := <-node.DataQueue :
			err := node.Conn.WriteMessage(websocket.TextMessage,data)
			if nil != err {
				log.Println(err.Error())
				return
			}
			fmt.Printf("%s",data)
		}
	}
}

/*
	启动协程接收逻辑
 */
func recvproc(node *Node)  {
	for  {
		_,data,err := node.Conn.ReadMessage()
		if nil != err {
			log.Println(err.Error())
			return
		}
		fmt.Printf("%s",data)
		dispatch(data)
	}
}

func dispatch(data [] byte)  {
	//todo 解析data为msg
	msg := Message{}
	err := json.Unmarshal(data,&msg)
	if nil != err {
		log.Println(err.Error())
		return
	}
	//todo 根据cmd对逻辑处理
	switch msg.Cmd {
		//单聊
		case CMD_SINGLE_MSG:
			sendMsg(msg.Dstid,data)
		//群聊
		case CMD_ROOM_MSG:
			fmt.Printf("%s",data)
		case CMD_HEART:
			//心跳什么都不做

	}

}

//发送消息，入通道
func sendMsg(userId int64, msg [] byte)  {
	//加写锁
	rwlocker.RLock()
	node,ok := clientMap[userId]
	rwlocker.RUnlock()
	if ok {
		node.DataQueue <- msg
	}
}